package input;

import java.util.ArrayList;
import java.util.List;

import settings.CommonSettings;

import com.jme.input.AbsoluteMouse;
import com.jme.input.MouseInput;
import com.jme.input.MouseInputListener;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;

import fileHandling.TextureLoader;

/**
 * This will be used as the mouse-cursor. Extending {@link AbsoluteMouse}, this provides functionality 
 * to change the cursor on the fly and to set this mouse visible or invisible.
 * 
 * @author Wasserleiche
 */
public class Mouse extends AbsoluteMouse {
	
	public enum MouseMode { Crosshair, Menu, None }
	
	private static final int MIN_SIZE = 20;
	private static final int MAX_SIZE = 42;
	
	private static final long serialVersionUID = 1L;
	
	/** The path containing all cursor-textures. */
	private static final String CURSOR_PATH = "data/textures/gui/cursors/";
	
	private static TextureState menuState, noCursorState;
	private static List<TextureState> ingameCrosshairs;
	private static ColorRGBA defaultColor;
	private ColorRGBA ingameColor;
	
	/** The last cursor that has been used. */
	/** The current {@link TextureState} that is applied to the mouse. */
	private MouseMode lastCursor;
	private Vector3f currentHotSpot;
	
	/**
	 * Constructs a new Mouse. This initializes a {@link Menu}-cursor and the {@link BlendState} for this 
	 * Mouse. The position of the mouse will be set to the middle of the screen.
	 * @param display The current {@link DisplaySystem}.
	 */
	public Mouse() {
		super("Ingame Mouse", DisplaySystem.getDisplaySystem().getWidth(), 
				DisplaySystem.getDisplaySystem().getHeight());
		
		DisplaySystem display = DisplaySystem.getDisplaySystem();
		
		initCursorStates();
		updateCommonSettings();
		
		setCursor(MouseMode.Menu);
		
		BlendState bs = display.getRenderer().createBlendState();
		bs.setBlendEnabled(true);
		bs.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
		bs.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
		bs.setTestEnabled(true);
		bs.setTestFunction(BlendState.TestFunction.GreaterThan);
		setRenderState(bs);
		
		setRenderQueueMode(Renderer.QUEUE_ORTHO);
		
		updateRenderState();
		
		MouseInput.get().addListener(new MouseInputListener() {
			@Override
			public void onWheel(int wheelDelta, int x, int y) {}
			@Override
			public void onMove(int xDelta, int yDelta, int newX, int newY) {
				getLocalTranslation().set(newX, newY, 0f);
				if(lastCursor != MouseMode.Crosshair) 
					getLocalTranslation().addLocal(-currentHotSpot.x, -currentHotSpot.y, currentHotSpot.z);
			}
			@Override
			public void onButton(int button, boolean pressed, int x, int y) {}
		});
		
		updateSize();
	}
	
	private static void initCursorStates() {
		menuState = TextureLoader.getTextureState(CURSOR_PATH + "menuCursor.png");
		noCursorState = TextureLoader.getTextureState(CURSOR_PATH + "noCursor.png");
		
		defaultColor = ColorRGBA.white.clone();
		
		ingameCrosshairs = new ArrayList<TextureState>();
		for(int i = 0; i < CommonSettings.INSTALLED_MOUSE_CURSORS; i++) {
			ingameCrosshairs.add(TextureLoader.getTextureState(CURSOR_PATH + "ingame" + i + ".png"));
		}
	}
	
	public void updateCommonSettings() {
		updateColors();
		updateSize();
	}
	
	public void updateColors() {
		CommonSettings common = CommonSettings.get();
		float r = common.getCrosshairColorRed();
		float g = common.getCrosshairColorGreen();
		float b = common.getCrosshairColorBlue();
		float a = common.getCrosshairColorAlpha();
		ingameColor = new ColorRGBA(r, g, b, a);
		
		if(lastCursor == MouseMode.Crosshair) setSolidColor(ingameColor);
	}
	
	/**
	 * Changes the cursor-texture and updates the last cursor.
	 * @param cursor The new cursor-type to be set.
	 */
	public void setCursor(MouseMode mode) {
		if(mode != MouseMode.None) lastCursor = mode;
		switch(mode) {
			case Crosshair : {
				setRenderState(ingameCrosshairs.get(CommonSettings.get().getCrosshairType()));
				setSolidColor(ingameColor);
				break;
			}
			case Menu : {
				setRenderState(menuState);
				setSolidColor(defaultColor);
				break;
			}
			case None : {
				setRenderState(noCursorState);
				setSolidColor(defaultColor);
				break;
			}
		}
		updateRenderState();
		updateSize();
		currentHotSpot = getHotSpotOffset().clone();
	}
	
	public MouseMode getLastMode() { return lastCursor; }
	
	protected void updateSize() {
		float size = CommonSettings.get().getCrosshairSize();
		float quadSize = MIN_SIZE + (size * (MAX_SIZE - MIN_SIZE));
		resize(quadSize, quadSize);
	}
}